﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;

namespace T.FAS.Runtime.Base.Entity
{
    /// <summary>
    /// 数据变更集
    /// </summary>
    [Serializable]
    public class TChangeSet : DynamicObject, ICloneable
    {
        Dictionary<string, object> _properties;
        private List<TChangeSetItem> _changeSetItems = null;
        public List<TChangeSetItem> ChangeSetItems
        {
            get { return _changeSetItems; }
        }
        public TRecordChangeType ChangeType { get; set; }
        public string PKColumnName { get; set; }
        private string pkColumnValue;
        public string PKColumnValue
        {
            get
            {
                pkColumnValue = Convert.ToString(GetValue(PKColumnName));
                return pkColumnValue;
            }
            set
            {
                pkColumnValue = value;
            }
        }
        private string _modifier = string.Empty;
        /// <summary>
        /// 数据变更人
        /// </summary>
        public string Modifier
        {
            get { return _modifier; }
            set
            {
                this.SetValue("Modifier", value);
                _modifier = value;
            }
        }
        private string _modifierName = string.Empty;
        /// <summary>
        /// 数据变更人名称
        /// </summary>
        public string ModifierName
        {
            get { return _modifierName; }
            set
            {
                this.SetValue("ModifierName", value);
                _modifierName = value;
            }
        }
        private string _billID = string.Empty;
        /// <summary>
        /// 业务单据ID
        /// </summary>
        public string BillID
        {
            get { return _billID; }
            set
            {
                this.SetValue("BillID", value);
                _billID = value;
            }
        }
        private string _tenantID = string.Empty;
        /// <summary>
        /// 租户ID
        /// </summary>
        public string TenantID
        {
            get { return _tenantID; }
            set
            {
                this.SetValue("TenantID", value);
                _tenantID = value;
            }
        }
        public int Count
        {
            get
            {
                return ChangeSetItems == null ? 0 : ChangeSetItems.Count;
            }
        }
        private DateTime _modifyTime;
        /// <summary>
        /// 数据变更时间
        /// </summary>
        public DateTime ModifyTime
        {
            get { return _modifyTime; }
            set
            {
                this.SetValue("ModifyTime", value);
                _modifyTime = value;
            }
        }
        /// <summary>
        /// 变更的CDOID
        /// </summary>
        public string CDOID { get; set; }
        /// <summary>
        /// 变更的CDO编号
        /// </summary>
        public string CDOCode { get; set; }
        /// <summary>
        /// 变更的CDOName
        /// </summary>
        public string CDOName { get; set; }

        public TChangeSetItem this[string columnCode]
        {
            get
            {
                return GetChangeSetItemByColumnCode(columnCode);
            }
        }

        #region 构造函数
        public TChangeSet()
        {
            _changeSetItems = new List<TChangeSetItem>();
            _properties = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
        }
        public TChangeSet(TChangeSetItem item)
        {
            _changeSetItems = new List<TChangeSetItem>();
            _changeSetItems.Add(item);
            _properties = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
        }

        #endregion

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            string name = binder.Name;
            if (_properties.ContainsKey(name))
            {
                _properties[name] = value;
                return true;
            }
            else
            {
                return false;
            }
        }
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            string name = binder.Name;
            if (_properties.ContainsKey(name))
            {
                result = _properties[name];
                return true;
            }
            else
            {
                result = null;
                return false;
            }
        }

        public object GetValue(string propertyName)
        {
            if (_properties != null && !string.IsNullOrEmpty(propertyName) && _properties.ContainsKey(propertyName))
            {
                return _properties[propertyName];
            }
            return null;
        }
        public void SetValue(string propertyName, object dataValue)
        {
            if (_properties.ContainsKey(propertyName))
                _properties[propertyName] = dataValue;
            else
                _properties.Add(propertyName, dataValue);
        }
        
        /// <summary>
        /// 根据列编号获取变更数据
        /// </summary>
        /// <param name="columnCode"></param>
        /// <returns></returns>
        public TChangeSetItem GetChangeSetItemByColumnCode(string columnCode)
        {
            if (ChangeSetItems == null || ChangeSetItems.Count <= 0)
                return null;
            return ChangeSetItems.Find(x => x.ColumnCode.Equals(columnCode, StringComparison.OrdinalIgnoreCase));
        }

        /// <summary>
        /// 是否包含指定列的变更数据
        /// </summary>
        /// <param name="columnCode"></param>
        /// <returns></returns>
        public bool IsContain(string columnCode)
        {
            if (ChangeSetItems == null || ChangeSetItems.Count <= 0)
                return false;
            return ChangeSetItems.Exists(x => x.ColumnCode.Equals(columnCode, StringComparison.OrdinalIgnoreCase));
        }

        /// <summary>
        /// 获取所有有变更的列编号
        /// </summary>
        /// <returns></returns>
        public List<string> GetChangedColumnCodes()
        {
            if (ChangeSetItems == null || ChangeSetItems.Count <= 0)
                return new List<string>();
            return ChangeSetItems.Select(x => x.ColumnCode).ToList();
        }

        /// <summary>
        /// 增加变更数据
        /// </summary>
        /// <param name="data">变更数据</param>
        /// <param name="isReplaceExistData">是否要替换已存在的变更数据，如果是，进行数据替换；如果否，不进行数据添加</param>
        public void AddChangeSetItem(TChangeSetItem data, bool isReplaceExistData = true)
        {
            if (_changeSetItems == null)
                _changeSetItems = new List<TChangeSetItem>();
            if (string.IsNullOrEmpty(data.ColumnCode))
                return;
            if (ChangeSetItems.Exists(x => x.ColumnCode.Equals(data.ColumnCode)))
            {
                if (isReplaceExistData)
                {
                    var oldSortOrder = RemoveChangeData(data.ColumnCode);
                    if (oldSortOrder == -1)
                    {
                        data.SortOrder = ChangeSetItems.Count;
                    }
                    else
                        data.SortOrder = oldSortOrder;
                    ChangeSetItems.Add(data);
                    this.SetValue(data.ColumnCode, data);
                }
            }
            else
            {
                data.SortOrder = ChangeSetItems.Count;
                data.InitValue = data.OldValue;
                data.InitDisplayName = data.OldDisplayValue;
                ChangeSetItems.Add(data);
                this.SetValue(data.ColumnCode, data);
            }
        }

        /// <summary>
        /// 增加变更数据
        /// </summary>
        /// <param name="data">变更数据</param>
        /// <param name="isReplaceExistData">是否要替换已存在的变更数据，如果是，进行数据替换；如果否，不进行数据添加</param>
        public void AddRangeChangeData(List<TChangeSetItem> datas, bool isReplaceExistData = true)
        {
            datas.ForEach(data =>
            {
                AddChangeSetItem(data, isReplaceExistData);
            });
        }

        /// <summary>
        /// 按照列编号删除变更数据
        /// </summary>
        /// <param name="columnCode"></param>
        public int RemoveChangeData(string columnCode)
        {
            if (ChangeSetItems != null)
            {
                var item = ChangeSetItems.Find(x => x.ColumnCode.Equals(columnCode));
                if (item != null)
                {
                    ChangeSetItems.Remove(item);
                    return item.SortOrder;
                }
            }
            return -1;
        }

        public static TChangeSet BuildChangeSet(JObject data)
        {
            JToken changeSetItemsToken = default;
            JToken changeTypeToken = default;

            foreach (var prop in data.Properties())
            {
                if (string.Equals(prop.Name, nameof(ChangeSetItems)))
                {
                    changeSetItemsToken = prop.Value;
                }
                else if (string.Equals(prop.Name, nameof(ChangeType)))
                {
                    changeTypeToken = prop.Value;
                }
            }

            TChangeSet changeSet = new TChangeSet(); 
            if (changeTypeToken is JValue changeTypeVal && changeTypeVal.Type == JTokenType.Integer)
            {
                var changeTypeInt = Convert.ToInt32(changeTypeVal.Value == null ? 0 : changeTypeVal.Value);
                changeSet.ChangeType = (TRecordChangeType)Enum.Parse(typeof(TRecordChangeType), changeTypeInt.ToString());
            }
            if (changeSetItemsToken is JArray itmesArr)
            {
                List<TChangeSetItem> items = itmesArr.ToObject<List<TChangeSetItem>>();
                changeSet.AddRangeChangeData(items);

            }
            return changeSet;
        }

        public static JObject ToJson(TChangeSet changeSet)
        {
            var serializer = JsonSerializer.Create(CreateJsonSeriaSetting());
            if (changeSet == null) return default;
            var changeSetObj = new JObject();
            var arr = new JArray();
            foreach (var childP in changeSet.ChangeSetItems)
            {
                arr.Add(JObject.FromObject(childP, serializer));
            }
            changeSetObj[nameof(ChangeSetItems)] = arr;
            changeSetObj[nameof(ChangeType)] = new JValue(changeSet.ChangeType);
            return changeSetObj;
        }

        private static JsonSerializerSettings CreateJsonSeriaSetting()
        {
            var jsonResolver = new PropertyRenameAndIgnoreSerializerContractResolver();
            jsonResolver.IgnoreProperty(typeof(TChangeSetItem), nameof(TChangeSetItem.BusinessType));
            jsonResolver.IgnoreProperty(typeof(TChangeSetItem), nameof(TChangeSetItem.ColumnName));
            jsonResolver.IgnoreProperty(typeof(TChangeSetItem), nameof(TChangeSetItem.InitDisplayName));
            jsonResolver.IgnoreProperty(typeof(TChangeSetItem), nameof(TChangeSetItem.OldDisplayValue));
            jsonResolver.IgnoreProperty(typeof(TChangeSetItem), nameof(TChangeSetItem.NewDisplayValue));
            jsonResolver.IgnoreProperty(typeof(TChangeSetItem), nameof(TChangeSetItem.SortOrder));
            var serializerSettings = new JsonSerializerSettings();
            serializerSettings.ContractResolver = jsonResolver;
            return serializerSettings;
        }

        public object Clone()
        {
            throw new NotImplementedException();
        }
    }
}
